Completed
Push — master ( 17669b...b8e030 )
by Rain
02:40
created

ko.bindingHandlers.popover.init   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
nop 2

1 Function

Rating   Name   Duplication   Size   Complexity  
A 0 3 1
1
2
import window from 'window';
3
import _ from '_';
4
import $ from '$';
5
import Opentip from 'Opentip';
6
import Pikaday from 'pikaday';
7
8
import {SaveSettingsStep, Magics} from 'Common/Enums';
9
10
const
11
	ko = window.ko,
12
	$win = $(window),
13
	fDisposalTooltipHelper = (element) => {
14
		ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
15
			if (element && element.__opentip)
16
			{
17
				element.__opentip.deactivate();
18
			}
19
		});
20
	};
21
22
ko.bindingHandlers.updateWidth = {
23
	init: (element, fValueAccessor) => {
24
		const
25
			$el = $(element),
26
			fValue = fValueAccessor(),
27
			fInit = () => {
28
				fValue($el.width());
29
				window.setTimeout(() => {
30
					fValue($el.width());
31
				}, Magics.Time500ms);
32
			};
33
34
		$win.on('resize', fInit);
35
		fInit();
36
37
		ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
38
			$win.off('resize', fInit);
39
		});
40
	}
41
};
42
43
ko.bindingHandlers.editor = {
44
	init: (element, fValueAccessor) => {
45
46
		let editor = null;
47
48
		const
49
			fValue = fValueAccessor(),
50
			HtmlEditor = require('Common/HtmlEditor').default,
51
			fUpdateEditorValue = () => {
52
				if (fValue && fValue.__editor)
53
				{
54
					fValue.__editor.setHtmlOrPlain(fValue());
55
				}
56
			},
57
			fUpdateKoValue = () => {
58
				if (fValue && fValue.__editor)
59
				{
60
					fValue(fValue.__editor.getDataWithHtmlMark());
61
				}
62
			},
63
			fOnReady = () => {
64
				fValue.__editor = editor;
65
				fUpdateEditorValue();
66
			};
67
68
		if (ko.isObservable(fValue) && HtmlEditor)
69
		{
70
			editor = new HtmlEditor(element, fUpdateKoValue, fOnReady, fUpdateKoValue);
71
72
			fValue.__fetchEditorValue = fUpdateKoValue;
73
74
			fValue.subscribe(fUpdateEditorValue);
75
76
//			ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
77
//			});
78
		}
79
	}
80
};
81
82
ko.bindingHandlers.json = {
83
	init: (element, fValueAccessor) => {
84
		$(element).text(window.JSON.stringify(ko.unwrap(fValueAccessor())));
85
	},
86
	update: (element, fValueAccessor) => {
87
		$(element).text(window.JSON.stringify(ko.unwrap(fValueAccessor())));
88
	}
89
};
90
91
ko.bindingHandlers.scrollerShadows = {
92
	init: (element) => {
93
94
		const
95
			limit = 8,
96
			$el = $(element),
97
			cont = $el.find('[data-scroller-shadows-content]')[0] || null,
98
			fFunc = _.throttle(() => {
99
				$el
100
					.toggleClass('scroller-shadow-top', limit < cont.scrollTop)
101
					.toggleClass('scroller-shadow-bottom', cont.scrollTop + limit < cont.scrollHeight - cont.clientHeight);
102
			}, 100);
103
104
		if (cont)
105
		{
106
			$(cont).on('scroll resize', fFunc);
107
			$win.on('resize', fFunc);
108
109
			ko.utils.domNodeDisposal.addDisposeCallback(cont, () => {
110
				$(cont).off();
111
				$win.off('resize', fFunc);
112
			});
113
		}
114
	}
115
};
116
117
ko.bindingHandlers.pikaday = {
118
	init: (element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext) => {
119
120
		ko.bindingHandlers.textInput.init(element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext);
121
122
		if (Pikaday)
123
		{
124
			element.__pikaday = new Pikaday({
125
				field: element
126
			});
127
		}
128
	}
129
};
130
131
ko.bindingHandlers.visibleAnimated = {
132
	init: (element, fValueAccessor) => {
133
		const $el = $(element);
134
		$el.addClass('rl-animated-visible');
135
		if (ko.unwrap(fValueAccessor())) {
136
			$el.how();
137
		} else {
138
			$el.hide();
139
		}
140
	},
141
	update: (element, fValueAccessor) => {
142
		const $el = $(element);
143
		if (ko.unwrap(fValueAccessor())) {
144
			$el.addClass('rl-animated-hidden').show();
145
			_.delay(() => {
146
				$el.removeClass('rl-animated-hidden');
147
			}, 10);
148
		} else {
149
			$el.hide().removeClass('rl-animated-hidden');
150
		}
151
	}
152
};
153
154
ko.bindingHandlers.tooltip = {
155
	init: (element, fValueAccessor) => {
156
157
		const
158
			$el = $(element),
159
			fValue = fValueAccessor(),
160
			isMobile = 'on' === ($el.data('tooltip-mobile') || 'off'),
161
			Globals = require('Common/Globals');
162
163
		if (!Globals.bMobileDevice || isMobile)
164
		{
165
			const sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue);
166
167
			element.__opentip = new Opentip(element, {
168
				'style': 'rainloopTip',
169
				'element': element,
170
				'tipJoint': $el.data('tooltip-join') || 'bottom'
171
			});
172
173
			Globals.dropdownVisibility.subscribe((v) => {
174
				if (v) {
175
					element.__opentip.hide();
176
				}
177
			});
178
179
			if ('' === sValue)
180
			{
181
				element.__opentip.hide();
182
				element.__opentip.deactivate();
183
				element.__opentip.setContent('');
184
			}
185
			else
186
			{
187
				element.__opentip.activate();
188
			}
189
190
			if ('on' === ($el.data('tooltip-i18n') || 'on'))
191
			{
192
				const Translator = require('Common/Translator');
193
194
				element.__opentip.setContent(Translator.i18n(sValue));
195
196
				Translator.trigger.subscribe(() => {
197
					element.__opentip.setContent(Translator.i18n(sValue));
198
				});
199
200
				Globals.dropdownVisibility.subscribe(() => {
201
					if (element && element.__opentip)
202
					{
203
						element.__opentip.setContent(Translator.i18n(sValue));
204
					}
205
				});
206
			}
207
			else
208
			{
209
				element.__opentip.setContent(sValue);
210
			}
211
		}
212
	},
213
	update: (element, fValueAccessor) => {
214
215
		const
216
			$el = $(element),
217
			fValue = fValueAccessor(),
218
			isMobile = 'on' === ($el.data('tooltip-mobile') || 'off'),
219
			Globals = require('Common/Globals');
220
221
		if ((!Globals.bMobileDevice || isMobile) && element.__opentip)
222
		{
223
			const sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue);
224
			if (sValue)
225
			{
226
				element.__opentip.setContent('on' === ($el.data('tooltip-i18n') || 'on') ?
227
					require('Common/Translator').i18n(sValue) : sValue);
228
229
				element.__opentip.activate();
230
			}
231
			else
232
			{
233
				element.__opentip.hide();
234
				element.__opentip.deactivate();
235
				element.__opentip.setContent('');
236
			}
237
		}
238
	}
239
};
240
241
ko.bindingHandlers.tooltipErrorTip = {
242
	init: function(element) {
243
244
		const $el = $(element);
245
246
		element.__opentip = new Opentip(element, {
247
			style: 'rainloopErrorTip',
248
			hideOn: 'mouseout click',
249
			element: element,
250
			tipJoint: $el.data('tooltip-join') || 'top'
251
		});
252
253
		element.__opentip.deactivate();
254
255
		$(window.document).on('click', () => {
256
			if (element && element.__opentip)
257
			{
258
				element.__opentip.hide();
259
			}
260
		});
261
262
		fDisposalTooltipHelper(element);
263
	},
264
	update: (element, fValueAccessor) => {
265
266
		const
267
			$el = $(element),
268
			fValue = fValueAccessor(),
269
			value = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue),
270
			openTips = element.__opentip;
271
272
		if (openTips)
273
		{
274
			if ('' === value)
275
			{
276
				openTips.hide();
277
				openTips.deactivate();
278
				openTips.setContent('');
279
			}
280
			else
281
			{
282
				_.delay(() => {
283
					if ($el.is(':visible'))
284
					{
285
						openTips.setContent(value);
286
						openTips.activate();
287
						openTips.show();
288
					}
289
					else
290
					{
291
						openTips.hide();
292
						openTips.deactivate();
293
						openTips.setContent('');
294
					}
295
				}, Magics.Time100ms);
296
			}
297
		}
298
	}
299
};
300
301
ko.bindingHandlers.registrateBootstrapDropdown = {
302
	init: (element) => {
303
		const Globals = require('Common/Globals');
304
		if (Globals && Globals.data.aBootstrapDropdowns)
305
		{
306
			Globals.data.aBootstrapDropdowns.push($(element));
307
308
			$(element).click(() => {
309
				require('Common/Utils').detectDropdownVisibility();
310
			});
311
312
//			ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
313
//			});
314
		}
315
	}
316
};
317
318
ko.bindingHandlers.openDropdownTrigger = {
319
	update: (element, fValueAccessor) => {
320
		if (ko.unwrap(fValueAccessor()))
321
		{
322
			const $el = $(element);
323
			if (!$el.hasClass('open'))
324
			{
325
				$el.find('.dropdown-toggle').dropdown('toggle');
326
			}
327
328
			$el.find('.dropdown-toggle').focus();
329
330
			require('Common/Utils').detectDropdownVisibility();
331
			fValueAccessor()(false);
332
		}
333
	}
334
};
335
336
ko.bindingHandlers.dropdownCloser = {
337
	init: (element) => {
338
		$(element).closest('.dropdown').on('click', '.e-item', () => {
339
			$(element).dropdown('toggle');
340
		});
341
	}
342
};
343
344
ko.bindingHandlers.popover = {
345
	init: function(element, fValueAccessor) {
346
		$(element).popover(ko.unwrap(fValueAccessor()));
347
348
		ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
349
			$(element).popover('destroy');
350
		});
351
	}
352
};
353
354
ko.bindingHandlers.csstext = {};
355
ko.bindingHandlers.csstext.init = ko.bindingHandlers.csstext.update = (element, fValueAccessor) => {
356
	if (element && element.styleSheet && 'undefined' !== typeof element.styleSheet.cssText)
357
	{
358
		element.styleSheet.cssText = ko.unwrap(fValueAccessor());
359
	}
360
	else
361
	{
362
		$(element).text(ko.unwrap(fValueAccessor()));
363
	}
364
};
365
366
ko.bindingHandlers.resizecrop = {
367
	init: (element) => {
368
		$(element).addClass('resizecrop').resizecrop({
369
			'width': '100',
370
			'height': '100',
371
			'wrapperCSS': {
372
				'border-radius': '10px'
373
			}
374
		});
375
	},
376
	update: (element, fValueAccessor) => {
377
		fValueAccessor()();
378
		$(element).resizecrop({
379
			'width': '100',
380
			'height': '100'
381
		});
382
	}
383
};
384
385
ko.bindingHandlers.onKeyDown = {
386
	init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => {
387
		$(element).on('keydown.koOnKeyDown', (event) => {
388
			if (event)
389
			{
390
				return fValueAccessor().call(viewModel, event);
391
			}
392
393
			return true;
394
		});
395
396
		ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
397
			$(element).off('keydown.koOnKeyDown');
398
		});
399
	}
400
};
401
402
ko.bindingHandlers.onEnter = {
403
	init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => {
404
		$(element).on('keypress.koOnEnter', (event) => {
405
			if (event && 13 === window.parseInt(event.keyCode, 10))
406
			{
407
				$(element).trigger('change');
408
				fValueAccessor().call(viewModel);
409
			}
410
		});
411
412
		ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
413
			$(element).off('keypress.koOnEnter');
414
		});
415
	}
416
};
417
418
ko.bindingHandlers.onSpace = {
419
	init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => {
420
		$(element).on('keyup.koOnSpace', (event) => {
421
			if (event && 32 === window.parseInt(event.keyCode, 10))
422
			{
423
				fValueAccessor().call(viewModel, event);
424
			}
425
		});
426
427
		ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
428
			$(element).off('keyup.koOnSpace');
429
		});
430
	}
431
};
432
433
ko.bindingHandlers.onTab = {
434
	init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => {
435
		$(element).on('keydown.koOnTab', (event) => {
436
			if (event && 9 === window.parseInt(event.keyCode, 10))
437
			{
438
				return fValueAccessor().call(viewModel, !!event.shiftKey);
439
			}
440
			return true;
441
		});
442
443
		ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
444
			$(element).off('keydown.koOnTab');
445
		});
446
	}
447
};
448
449
ko.bindingHandlers.onEsc = {
450
	init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => {
451
		$(element).on('keyup.koOnEsc', (event) => {
452
			if (event && 27 === window.parseInt(event.keyCode, 10))
453
			{
454
				$(element).trigger('change');
455
				fValueAccessor().call(viewModel);
456
			}
457
		});
458
459
		ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
460
			$(element).off('keyup.koOnEsc');
461
		});
462
	}
463
};
464
465
ko.bindingHandlers.clickOnTrue = {
466
	update: (element, fValueAccessor) => {
467
		if (ko.unwrap(fValueAccessor()))
468
		{
469
			$(element).click();
470
		}
471
	}
472
};
473
474
ko.bindingHandlers.modal = {
475
	init: (element, fValueAccessor) => {
476
477
		const
478
			Globals = require('Common/Globals'),
479
			Utils = require('Common/Utils');
480
481
		$(element)
482
			.toggleClass('fade', !Globals.bMobileDevice)
483
			.modal({
484
				'keyboard': false,
485
				'show': ko.unwrap(fValueAccessor())
486
			})
487
			.on('shown.koModal', Utils.windowResizeCallback)
488
			.find('.close').on('click.koModal', () => {
489
				fValueAccessor()(false);
490
			});
491
492
		ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
493
			$(element)
494
				.off('shown.koModal')
495
				.find('.close')
496
				.off('click.koModal');
497
		});
498
	},
499
	update: (element, fValueAccessor) => {
500
501
		const Globals = require('Common/Globals');
502
503
		$(element).modal(ko.unwrap(fValueAccessor()) ? 'show' : 'hide');
504
505
		if (Globals.$html.hasClass('rl-anim'))
506
		{
507
			Globals.$html.addClass('rl-modal-animation');
508
			_.delay(() => {
509
				Globals.$html.removeClass('rl-modal-animation');
510
			}, Magics.Time500ms);
511
		}
512
513
	}
514
};
515
516
ko.bindingHandlers.moment = {
517
	init: (element, fValueAccessor) => {
518
		require('Common/Momentor').momentToNode(
519
			$(element).addClass('moment').data('moment-time', ko.unwrap(fValueAccessor()))
520
		);
521
	},
522
	update: (element, fValueAccessor) => {
523
		require('Common/Momentor').momentToNode(
524
			$(element).data('moment-time', ko.unwrap(fValueAccessor()))
525
		);
526
	}
527
};
528
529
ko.bindingHandlers.i18nInit = {
530
	init: (element) => {
531
		require('Common/Translator').i18nToNodes(element);
532
	}
533
};
534
535
ko.bindingHandlers.translatorInit = {
536
	init: (element) => {
537
		require('Common/Translator').i18nToNodes(element);
538
	}
539
};
540
541
ko.bindingHandlers.i18nUpdate = {
542
	update: (element, fValueAccessor) => {
543
		ko.unwrap(fValueAccessor());
544
		require('Common/Translator').i18nToNodes(element);
545
	}
546
};
547
548
ko.bindingHandlers.link = {
549
	update: function(element, fValueAccessor) {
550
		$(element).attr('href', ko.unwrap(fValueAccessor()));
551
	}
552
};
553
554
ko.bindingHandlers.title = {
555
	update: function(element, fValueAccessor) {
556
		$(element).attr('title', ko.unwrap(fValueAccessor()));
557
	}
558
};
559
560
ko.bindingHandlers.textF = {
561
	init: function(element, fValueAccessor) {
562
		$(element).text(ko.unwrap(fValueAccessor()));
563
	}
564
};
565
566
ko.bindingHandlers.initDom = {
567
	init: function(element, fValueAccessor) {
568
		fValueAccessor()(element);
569
	}
570
};
571
572
ko.bindingHandlers.initFixedTrigger = {
573
	init: (element, fValueAccessor) => {
574
		const
575
			values = ko.unwrap(fValueAccessor()),
576
			$el = $(element),
577
			top = values[1] || 0;
578
579
		let $container = $(values[0] || null);
580
		$container = $container[0] ? $container : null;
581
		if ($container)
582
		{
583
			$win.resize(() => {
584
				const offset = $container.offset();
585
				if (offset && offset.top)
586
				{
587
					$el.css('top', offset.top + top);
588
				}
589
			});
590
		}
591
	}
592
};
593
594
ko.bindingHandlers.initResizeTrigger = {
595
	init: (element, fValueAccessor) => {
596
		const values = ko.unwrap(fValueAccessor());
597
		$(element).css({
598
			'height': values[1],
599
			'min-height': values[1]
600
		});
601
	},
602
	update: (oElement, fValueAccessor) => {
603
604
		const
605
			Utils = require('Common/Utils'),
606
			Globals = require('Common/Globals'),
607
			values = ko.unwrap(fValueAccessor());
608
609
		let
610
			value = Utils.pInt(values[1]),
611
			size = 0,
612
			offset = $(oElement).offset().top;
613
614
		if (0 < offset)
615
		{
616
			offset += Utils.pInt(values[2]);
617
			size = Globals.$win.height() - offset;
618
619
			if (value < size)
620
			{
621
				value = size;
622
			}
623
624
			$(oElement).css({
625
				'height': value,
626
				'min-height': value
627
			});
628
		}
629
	}
630
};
631
632
ko.bindingHandlers.appendDom = {
633
	update: (element, fValueAccessor) => {
634
		$(element).hide().empty().append(ko.unwrap(fValueAccessor())).show();
635
	}
636
};
637
638
ko.bindingHandlers.draggable = {
639
	init: (element, fValueAccessor, fAllBindingsAccessor) => {
640
641
		const
642
			Globals = require('Common/Globals'),
643
			Utils = require('Common/Utils');
644
645
		if (!Globals.bMobileDevice)
646
		{
647
			const
648
				triggerZone = 100,
649
				scrollSpeed = 3,
650
				fAllValueFunc = fAllBindingsAccessor(),
651
				droppableSelector = fAllValueFunc && fAllValueFunc.droppableSelector ? fAllValueFunc.droppableSelector : '',
652
				conf = {
653
					distance: 20,
654
					handle: '.dragHandle',
655
					cursorAt: {top: 22, left: 3},
656
					refreshPositions: true,
657
					scroll: true
658
				};
659
660
			if (droppableSelector)
661
			{
662
				conf.drag = (event) => {
663
664
					$(droppableSelector).each(function() {
665
						const
666
							$this = $(this), // eslint-disable-line no-invalid-this
667
							offset = $this.offset(),
668
							bottomPos = offset.top + $this.height();
669
670
						window.clearInterval($this.data('timerScroll'));
671
						$this.data('timerScroll', false);
672
673
						if (event.pageX >= offset.left && event.pageX <= offset.left + $this.width())
674
						{
675
							if (event.pageY >= bottomPos - triggerZone && event.pageY <= bottomPos)
676
							{
677
								const moveUp = () => {
678
									$this.scrollTop($this.scrollTop() + scrollSpeed);
679
									Utils.windowResize();
680
								};
681
682
								$this.data('timerScroll', window.setInterval(moveUp, 10));
683
								moveUp();
684
							}
685
686
							if (event.pageY >= offset.top && event.pageY <= offset.top + triggerZone)
687
							{
688
								const moveDown = () => {
689
									$this.scrollTop($this.scrollTop() - scrollSpeed);
690
									Utils.windowResize();
691
								};
692
693
								$this.data('timerScroll', window.setInterval(moveDown, 10));
694
								moveDown();
695
							}
696
						}
697
					});
698
				};
699
700
				conf.stop = () => {
701
					$(droppableSelector).each(function() {
702
						const $this = $(this); // eslint-disable-line no-invalid-this
703
						window.clearInterval($this.data('timerScroll'));
704
						$this.data('timerScroll', false);
705
					});
706
				};
707
			}
708
709
			conf.helper = (event) => fValueAccessor()(event && event.target ? ko.dataFor(event.target) : null);
710
711
			$(element).draggable(conf).on('mousedown.koDraggable', () => {
712
				Utils.removeInFocus();
713
			});
714
715
			ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
716
				$(element)
717
					.off('mousedown.koDraggable')
718
					.draggable('destroy');
719
			});
720
		}
721
	}
722
};
723
724
ko.bindingHandlers.droppable = {
725
	init: (element, fValueAccessor, fAllBindingsAccessor) => {
726
		const Globals = require('Common/Globals');
727
		if (!Globals.bMobileDevice)
728
		{
729
			const
730
				fValueFunc = fValueAccessor(),
731
				fAllValueFunc = fAllBindingsAccessor(),
732
				fOverCallback = fAllValueFunc && fAllValueFunc.droppableOver ? fAllValueFunc.droppableOver : null,
733
				fOutCallback = fAllValueFunc && fAllValueFunc.droppableOut ? fAllValueFunc.droppableOut : null,
734
				conf = {
735
					tolerance: 'pointer',
736
					hoverClass: 'droppableHover'
737
				};
738
739
			if (fValueFunc)
740
			{
741
				conf.drop = (event, ui) => {
742
					fValueFunc(event, ui);
743
				};
744
745
				if (fOverCallback)
746
				{
747
					conf.over = (event, ui) => {
748
						fOverCallback(event, ui);
749
					};
750
				}
751
752
				if (fOutCallback)
753
				{
754
					conf.out = (event, ui) => {
755
						fOutCallback(event, ui);
756
					};
757
				}
758
759
				$(element).droppable(conf);
760
761
				ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
762
					$(element).droppable('destroy');
763
				});
764
			}
765
		}
766
	}
767
};
768
769
ko.bindingHandlers.nano = {
770
	init: (element) => {
771
772
		const
773
			Globals = require('Common/Globals'),
774
			Settings = require('Storage/Settings');
775
776
		if (!Globals.bDisableNanoScroll && !Settings.appSettingsGet('useNativeScrollbars'))
777
		{
778
			$(element)
779
				.addClass('nano')
780
				.nanoScroller({
781
					iOSNativeScrolling: false,
782
					preventPageScrolling: true
783
				});
784
		}
785
	}
786
};
787
788
ko.bindingHandlers.saveTrigger = {
789
	init: (element) => {
790
791
		const $el = $(element);
792
793
		$el.data('save-trigger-type', $el.is('input[type=text],input[type=email],input[type=password],select,textarea') ? 'input' : 'custom');
794
795
		if ('custom' === $el.data('save-trigger-type'))
796
		{
797
			$el.append(
798
				'&nbsp;&nbsp;<i class="icon-spinner animated"></i><i class="icon-remove error"></i><i class="icon-ok success"></i>'
799
			).addClass('settings-saved-trigger');
800
		}
801
		else
802
		{
803
			$el.addClass('settings-saved-trigger-input');
804
		}
805
	},
806
	update: (element, fValueAccessor) => {
807
		const
808
			value = ko.unwrap(fValueAccessor()),
809
			$el = $(element);
810
811
		if ('custom' === $el.data('save-trigger-type'))
812
		{
813
			switch (value.toString())
814
			{
815
				case '1':
816
					$el
817
						.find('.animated,.error').hide().removeClass('visible')
818
						.end()
819
						.find('.success').show().addClass('visible');
820
					break;
821
				case '0':
822
					$el
823
						.find('.animated,.success').hide().removeClass('visible')
824
						.end()
825
						.find('.error').show().addClass('visible');
826
					break;
827
				case '-2':
828
					$el
829
						.find('.error,.success').hide().removeClass('visible')
830
						.end()
831
						.find('.animated').show().addClass('visible');
832
					break;
833
				default:
834
					$el
835
						.find('.animated').hide()
836
						.end()
837
						.find('.error,.success').removeClass('visible');
838
					break;
839
			}
840
		}
841
		else
842
		{
843
			switch (value.toString())
844
			{
845
				case '1':
846
					$el.addClass('success').removeClass('error');
847
					break;
848
				case '0':
849
					$el.addClass('error').removeClass('success');
850
					break;
851
				case '-2':
852
					break;
853
				default:
854
					$el.removeClass('error success');
855
					break;
856
			}
857
		}
858
	}
859
};
860
861
ko.bindingHandlers.emailsTags = {
862
	init: (element, fValueAccessor, fAllBindingsAccessor) => {
863
864
		const
865
			Utils = require('Common/Utils'),
866
			EmailModel = require('Model/Email').default,
867
868
			$el = $(element),
869
			fValue = fValueAccessor(),
870
			fAllBindings = fAllBindingsAccessor(),
871
			fAutoCompleteSource = fAllBindings.autoCompleteSource || null,
872
			fFocusCallback = (value) => {
873
				if (fValue && fValue.focused)
874
				{
875
					fValue.focused(!!value);
876
				}
877
			};
878
879
		$el.inputosaurus({
880
			parseOnBlur: true,
881
			allowDragAndDrop: true,
882
			focusCallback: fFocusCallback,
883
			inputDelimiters: [',', ';', '\n'],
884
			autoCompleteSource: fAutoCompleteSource,
885
//			elementHook: (el, item) => {
886
//				if (el && item)
887
//				{
888
//					el.addClass('pgp');
889
//				}
890
//			},
891
			parseHook: (input) => _.map(input, (inputValue) => {
892
				const value = Utils.trim(inputValue);
893
				if ('' !== value)
894
				{
895
					const email = new EmailModel();
896
					email.mailsoParse(value);
897
					return [email.toLine(false), email];
898
				}
899
				return [value, null];
900
901
			}),
902
			'change': (event) => {
903
				$el.data('EmailsTagsValue', event.target.value);
904
				fValue(event.target.value);
905
			}
906
		});
907
908
		if (fValue && fValue.focused && fValue.focused.subscribe)
909
		{
910
			fValue.focused.subscribe((value) => {
911
				$el.inputosaurus(value ? 'focus' : 'blur');
912
			});
913
		}
914
	},
915
	update: (element, fValueAccessor) => {
916
917
		const
918
			$oEl = $(element),
919
			fValue = fValueAccessor(),
920
			value = ko.unwrap(fValue);
921
922
		if ($oEl.data('EmailsTagsValue') !== value)
923
		{
924
			$oEl.val(value);
925
			$oEl.data('EmailsTagsValue', value);
926
			$oEl.inputosaurus('refresh');
927
		}
928
	}
929
};
930
931
ko.bindingHandlers.command = {
932
	init: (element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext) => {
933
		const
934
			jqElement = $(element),
935
			oCommand = fValueAccessor();
936
937
		if (!oCommand || !oCommand.enabled || !oCommand.canExecute)
938
		{
939
			throw new Error('You are not using command function');
940
		}
941
942
		jqElement.addClass('command');
943
		ko.bindingHandlers[jqElement.is('form') ? 'submit' : 'click']
944
			.init(element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext);
945
	},
946
	update: (element, fValueAccessor) => {
947
948
		const
949
			jqElement = $(element),
950
			command = fValueAccessor();
951
952
		let result = command.enabled();
953
954
		jqElement.toggleClass('command-not-enabled', !result);
955
956
		if (result)
957
		{
958
			result = command.canExecute();
959
			jqElement.toggleClass('command-can-not-be-execute', !result);
960
		}
961
962
		jqElement.toggleClass('command-disabled disable disabled', !result).toggleClass('no-disabled', !!result);
963
964
		if (jqElement.is('input') || jqElement.is('button'))
965
		{
966
			jqElement.prop('disabled', !result);
967
		}
968
	}
969
};
970
971
// extenders
972
973
ko.extenders.trimmer = (target) => {
974
	const
975
		Utils = require('Common/Utils'),
976
		result = ko.computed({
977
			read: target,
978
			write: (newValue) => {
979
				target(Utils.trim(newValue.toString()));
980
			}
981
		});
982
983
	result(target());
984
	return result;
985
};
986
987
ko.extenders.posInterer = (target, defaultVal) => {
988
	const
989
		Utils = require('Common/Utils'),
990
		result = ko.computed({
991
			read: target,
992
			write: (newValue) => {
993
				let val = Utils.pInt(newValue.toString(), defaultVal);
994
				if (0 >= val)
995
				{
996
					val = defaultVal;
997
				}
998
999
				if (val === target() && '' + val !== '' + newValue)
1000
				{
1001
					target(val + 1);
1002
				}
1003
1004
				target(val);
1005
			}
1006
		});
1007
1008
	result(target());
1009
	return result;
1010
};
1011
1012
ko.extenders.limitedList = (target, limitedList) => {
1013
	const
1014
		Utils = require('Common/Utils'),
1015
		result = ko.computed({
1016
			read: target,
1017
			write: (newValue) => {
1018
1019
				const
1020
					currentValue = ko.unwrap(target),
1021
					list = ko.unwrap(limitedList);
1022
1023
				if (Utils.isNonEmptyArray(list))
1024
				{
1025
					if (-1 < Utils.inArray(newValue, list))
1026
					{
1027
						target(newValue);
1028
					}
1029
					else if (-1 < Utils.inArray(currentValue, list))
1030
					{
1031
						target(currentValue + ' ');
1032
						target(currentValue);
1033
					}
1034
					else
1035
					{
1036
						target(list[0] + ' ');
1037
						target(list[0]);
1038
					}
1039
				}
1040
				else
1041
				{
1042
					target('');
1043
				}
1044
			}
1045
		}).extend({notify: 'always'});
1046
1047
	result(target());
1048
1049
	if (!result.valueHasMutated)
1050
	{
1051
		result.valueHasMutated = () => {
1052
			target.valueHasMutated();
1053
		};
1054
	}
1055
1056
	return result;
1057
};
1058
1059
ko.extenders.reversible = (target) => {
1060
1061
	let value = target();
1062
1063
	target.commit = () => {
1064
		value = target();
1065
	};
1066
1067
	target.reverse = () => {
1068
		target(value);
1069
	};
1070
1071
	target.commitedValue = () => value;
1072
	return target;
1073
};
1074
1075
ko.extenders.toggleSubscribe = (target, options) => {
1076
	target.subscribe(options[1], options[0], 'beforeChange');
1077
	target.subscribe(options[2], options[0]);
1078
	return target;
1079
};
1080
1081
ko.extenders.toggleSubscribeProperty = (target, options) => {
1082
1083
	const prop = options[1];
1084
	if (prop)
1085
	{
1086
		target.subscribe((prev) => {
1087
			if (prev && prev[prop])
1088
			{
1089
				prev[prop](false);
1090
			}
1091
		}, options[0], 'beforeChange');
1092
1093
		target.subscribe((next) => {
1094
			if (next && next[prop])
1095
			{
1096
				next[prop](true);
1097
			}
1098
		}, options[0]);
1099
	}
1100
1101
	return target;
1102
};
1103
1104
ko.extenders.falseTimeout = (target, option) => {
1105
	target.iFalseTimeoutTimeout = 0;
1106
	target.subscribe((value) => {
1107
		if (value)
1108
		{
1109
			window.clearTimeout(target.iFalseTimeoutTimeout);
1110
			target.iFalseTimeoutTimeout = window.setTimeout(() => {
1111
				target(false);
1112
				target.iFalseTimeoutTimeout = 0;
1113
			}, require('Common/Utils').pInt(option));
1114
		}
1115
	});
1116
1117
	return target;
1118
};
1119
1120
ko.extenders.specialThrottle = (target, option) => {
1121
	target.iSpecialThrottleTimeoutValue = require('Common/Utils').pInt(option);
1122
	if (0 < target.iSpecialThrottleTimeoutValue)
1123
	{
1124
		target.iSpecialThrottleTimeout = 0;
1125
		target.valueForRead = ko.observable(!!target()).extend({throttle: 10});
1126
1127
		return ko.computed({
1128
			read: target.valueForRead,
1129
			write: (bValue) => {
1130
1131
				if (bValue)
1132
				{
1133
					target.valueForRead(bValue);
1134
				}
1135
				else
1136
				{
1137
					if (target.valueForRead())
1138
					{
1139
						window.clearTimeout(target.iSpecialThrottleTimeout);
1140
						target.iSpecialThrottleTimeout = window.setTimeout(() => {
1141
							target.valueForRead(false);
1142
							target.iSpecialThrottleTimeout = 0;
1143
						}, target.iSpecialThrottleTimeoutValue);
1144
					}
1145
					else
1146
					{
1147
						target.valueForRead(bValue);
1148
					}
1149
				}
1150
			}
1151
		});
1152
	}
1153
1154
	return target;
1155
};
1156
1157
ko.extenders.idleTrigger = (target) => {
1158
	target.trigger = ko.observable(SaveSettingsStep.Idle);
1159
	return target;
1160
};
1161
1162
// functions
1163
1164
ko.observable.fn.idleTrigger = function() {
1165
	return this.extend({'idleTrigger': true});
1166
};
1167
1168
ko.observable.fn.validateNone = function() {
1169
	this.hasError = ko.observable(false);
1170
	return this;
1171
};
1172
1173
ko.observable.fn.validateEmail = function() {
1174
1175
	this.hasError = ko.observable(false);
1176
1177
	this.subscribe((value) => {
1178
		this.hasError('' !== value && !(/^[^@\s]+@[^@\s]+$/.test(value)));
1179
	});
1180
1181
	this.valueHasMutated();
1182
	return this;
1183
};
1184
1185
ko.observable.fn.validateSimpleEmail = function() {
1186
1187
	this.hasError = ko.observable(false);
1188
1189
	this.subscribe((value) => {
1190
		this.hasError('' !== value && !(/^.+@.+$/.test(value)));
1191
	});
1192
1193
	this.valueHasMutated();
1194
	return this;
1195
};
1196
1197
ko.observable.fn.deleteAccessHelper = function() {
1198
	this.extend({falseTimeout: 3000}).extend({toggleSubscribeProperty: [this, 'deleteAccess']});
1199
	return this;
1200
};
1201
1202
ko.observable.fn.validateFunc = function(fFunc) {
1203
1204
	this.hasFuncError = ko.observable(false);
1205
1206
	if (_.isFunction(fFunc))
1207
	{
1208
		this.subscribe((value) => {
1209
			this.hasFuncError(!fFunc(value));
1210
		});
1211
1212
		this.valueHasMutated();
1213
	}
1214
1215
	return this;
1216
};
1217
1218
module.exports = ko;
1219